#include "ParserYAML.h"

using namespace parser;

void operator >>(const YAML::Node& node, InformacionMateriaYAML& informacionMateriaYAML) 
{
	node["codigo"] >> informacionMateriaYAML.codigo;
	node["nombre"] >> informacionMateriaYAML.nombre;
	node["creditos"] >> informacionMateriaYAML.creditos;

	const YAML::Node& nodoCatedras = node[YAML_NODO_CATEDRAS];
	for (unsigned i = 0; i < nodoCatedras.size(); i++) {
		CatedraMateriaYAML catedraMateriaYAML;
		
		nodoCatedras[i]["descripcion"] >> catedraMateriaYAML.descripcion;
		const YAML::Node& nodoDiasCursada = nodoCatedras[i][YAML_NODO_DIAS_CURSADA];
		for (unsigned i = 0; i < nodoDiasCursada.size(); i++) {
			DiaCursadaYAML diaCursadaYAML;
			string horario;

			nodoDiasCursada[i]["dia_semana"] >> diaCursadaYAML.diaDeLaSemana;
			nodoDiasCursada[i]["sede"] >> diaCursadaYAML.sede;
			nodoDiasCursada[i]["horario"] >> horario;

			int posSeparador = horario.find('-', 0);
			string horaDesde = horario.substr(0,posSeparador);
			string horaHasta = horario.substr(posSeparador + 1, horario.length());
			
			int posSeparadorDesde = horaDesde.find(':',0);
			int posSeparadorHasta = horaHasta.find(':',0);
			diaCursadaYAML.horaDesde.horas = atoi(horaDesde.substr(0,posSeparadorDesde).c_str());
			diaCursadaYAML.horaDesde.minutos = atoi(horaDesde.substr(posSeparadorDesde + 1,horaDesde.length()).c_str()); 
			diaCursadaYAML.horaHasta.horas = atoi(horaHasta.substr(0,posSeparadorHasta).c_str());
			diaCursadaYAML.horaHasta.minutos = atoi(horaHasta.substr(posSeparadorHasta + 1,horaHasta.length()).c_str());

			catedraMateriaYAML.diasCursada.push_back(diaCursadaYAML);
		}
		informacionMateriaYAML.catedras.push_back(catedraMateriaYAML);
	}
};

void operator >>(const YAML::Node& node, InformacionCarreraYAML& informacionCarreraYAML) 
{
	node["nombre_carrera"] >> informacionCarreraYAML.nombreCarrera;
	node["creditos_materias_obligatorias"] >> informacionCarreraYAML.creditosMateriasObligatorias;
	node["creditos_materias_optativas"] >> informacionCarreraYAML.creditosMateriasOptativas;
	node["cantidad_materias_optativas"] >> informacionCarreraYAML.cantidadMateriasOptativas;

	const YAML::Node& nodoMateriasObligatorias = node[YAML_NODO_MATERIAS_OBLIGATORIAS];
	for (unsigned i = 0; i < nodoMateriasObligatorias.size(); i++) {
		InformacionMateriaSegunCarreraYAML informacionMateriaObligatoriaYAML;
		
		nodoMateriasObligatorias[i]["codigo"] >> informacionMateriaObligatoriaYAML.codigo;
		nodoMateriasObligatorias[i]["correlativas"] >> informacionMateriaObligatoriaYAML.correlativas;
		informacionMateriaObligatoriaYAML.esObligatoria = true;

		informacionCarreraYAML.informacionMateriasObligatorias.push_back(informacionMateriaObligatoriaYAML);
	}

	const YAML::Node& nodoMateriasOptativas = node[YAML_NODO_MATERIAS_OPTATIVAS];
	for (unsigned i = 0; i < nodoMateriasOptativas.size(); i++) {
		InformacionMateriaSegunCarreraYAML informacionMateriaOptativaYAML;
		
		nodoMateriasOptativas[i]["codigo"] >> informacionMateriaOptativaYAML.codigo;
		nodoMateriasOptativas[i]["correlativas"] >> informacionMateriaOptativaYAML.correlativas;
		informacionMateriaOptativaYAML.esObligatoria = false;

		informacionCarreraYAML.informacionMateriasOptativas.push_back(informacionMateriaOptativaYAML);
	}
};

void operator >>(const YAML::Node& node, InformacionRestriccionesDeterministicasYAML& restriccionYAML) 
{
	node["materias_maximas_por_cuatrimestre"] >> restriccionYAML.materiasMaximasPorCuatr;

	const YAML::Node& nodoOptativasACursar = node[YAML_NODO_MATERIAS_OPTATIVAS_A_CURSAR];
	for (unsigned i = 0; i < nodoOptativasACursar.size(); i++) {
		string codigo;
		nodoOptativasACursar[i]["codigo"] >> codigo;
		restriccionYAML.materiasOptativasACursar.push_back(codigo);
	}

	const YAML::Node& nodoOptativasANoCursar = node[YAML_NODO_MATERIAS_OPTATIVAS_A_NO_CURSAR];
	for (unsigned i = 0; i < nodoOptativasANoCursar.size(); i++) {
		string codigo;
		nodoOptativasANoCursar[i]["codigo"] >> codigo;
		restriccionYAML.materiasOptativasANoCursar.push_back(codigo);
	}

	const YAML::Node& disponibilidadHoraria = node[YAML_NODO_DISPONIBILIDAD_HORARIA];
	for (unsigned i = 0; i < disponibilidadHoraria.size(); i++) {
		DisponibilidadHorariaDiariaYAML disponibilidadHorariaYAML;
		disponibilidadHoraria[i]["dia"] >> disponibilidadHorariaYAML.dia;
		disponibilidadHoraria[i]["horario"] >> disponibilidadHorariaYAML.horario;
		restriccionYAML.disponibilidadHoraria.push_back(disponibilidadHorariaYAML);
	}
};

void operator >>(const YAML::Node& node, InformacionRestriccionesNoDeterministicasYAML& restriccionYAML) 
{
	node["materias_dificultosas_maximas_por_cuatrimestre"] >> restriccionYAML.materiasDificultosasMaximasPorCuatrimestre;
	node["ajustar_plan_a_materias_sin_chequeo_asistencia"] >> restriccionYAML.ajustarPlanAMateriasSinChequeoAsistencia;
	node["ajustar_plan_omitiendo_optativas_prescindibles"] >> restriccionYAML.ajustarPlanOmitiendoOptativasPrescindibles;
};

ParserYAML::ParserYAML() 
{
};


InformacionCarreraYAML ParserYAML::ParsearArchivoInformacionDeCarrera(string ruta) 
{
	InformacionCarreraYAML informacionCarreraYAML;
	auto_ptr<YAML::Node> nodoRaiz = this->ObtenerNodoRaiz(ruta, YAML_NODO_RAIZ_INFO_CARRERA);
	const YAML::Node& nodoInformacionCarrera = (*nodoRaiz.get());
	nodoInformacionCarrera >> informacionCarreraYAML;
	return informacionCarreraYAML;
};

InformacionRestriccionesDeterministicasYAML ParserYAML::ParsearArchivoRestriccionesDeterministicas(string ruta)
{
	InformacionRestriccionesDeterministicasYAML restriccionesDeterministicas;
	auto_ptr<YAML::Node> nodoRaiz = this->ObtenerNodoRaiz(ruta, YAML_NODO_RAIZ_RESTRICCIONES_DETERMINISTICAS);
	const YAML::Node& nodoRestriccionesDeterministicas = (*nodoRaiz.get());
	nodoRestriccionesDeterministicas >> restriccionesDeterministicas;
	return restriccionesDeterministicas;
};
		
InformacionRestriccionesNoDeterministicasYAML ParserYAML::ParsearArchivoRestriccionesNoDeterministicas(string ruta)
{
	InformacionRestriccionesNoDeterministicasYAML restriccionesNoDeterministicas;
	auto_ptr<YAML::Node> nodoRaiz = this->ObtenerNodoRaiz(ruta, YAML_NODO_RAIZ_RESTRICCIONES_NO_DETERMINISTICAS);
	const YAML::Node& nodoRestriccionesNoDeterministicas = (*nodoRaiz.get());
	nodoRestriccionesNoDeterministicas >> restriccionesNoDeterministicas;
	return restriccionesNoDeterministicas;
};

list<InformacionMateriaYAML> ParserYAML::ParsearArchivoInformacionDeMaterias(string ruta)
{
	list<InformacionMateriaYAML> informacionMaterias;
	auto_ptr<YAML::Node> nodoRaiz = this->ObtenerNodoRaiz(ruta, YAML_NODO_RAIZ_INFORMACION_MATERIAS);
	const YAML::Node& nodoInformacionMaterias = (*nodoRaiz.get());
	for (unsigned i = 0; i < nodoInformacionMaterias.size(); i++) 
	{
		InformacionMateriaYAML informacionMateria;
		nodoInformacionMaterias[i] >> informacionMateria;
		informacionMaterias.push_back(informacionMateria);
	}
	return informacionMaterias;
};

std::auto_ptr<YAML::Node> ParserYAML::ObtenerNodoRaiz(string rutaArchivo, string raiz) 
{

	YAML::Node nodoRaiz;
	ifstream archivo;
	stringstream streamDatos;
	
	archivo = ifstream(rutaArchivo.c_str());	
	while(archivo.good())
	{
		char arch = archivo.get();
		streamDatos << arch;
	}
		
	YAML::Parser parser(streamDatos);
	parser.GetNextDocument(nodoRaiz);
	return nodoRaiz[raiz].Clone();
};